package com.houger.ddd.redpacket.integration.impl;

import com.houger.UidGenerator;
import com.houger.ddd.common.utils.DateUtil;
import com.houger.ddd.redpacket.application.GrabRedPacketAdaptor;
import com.houger.ddd.redpacket.application.RedPacketAdaptor;
import com.houger.ddd.redpacket.facade.dto.GrabRedPacketDto;
import com.houger.ddd.redpacket.facade.dto.RedPacketDto;
import com.houger.ddd.redpacket.controller.vo.GrabRedPacketResVo;
import com.houger.ddd.redpacket.domain.GrabRedPacketDomain;
import com.houger.ddd.redpacket.domain.RedPacketDomain;
import com.houger.ddd.redpacket.facade.RedPacketFacade;
import com.houger.ddd.redpacket.facade.UserClientFacade;
import com.houger.ddd.redpacket.integration.RedPacketService;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author Houger.
 * @date 2024年04月18日 15:47.
 */
@Service
public class RedPacketServiceImpl implements RedPacketService {

    @Resource
    UserClientFacade userClientFacade;
    @Resource
    RedPacketFacade redPacketFacade;
    @Resource
    UidGenerator uidGenerator;

    @Override
    public String sendRedPacket(final RedPacketDto redPacketDto) {
        // 每个红包最少不能低于0.01
        final BigDecimal total = new BigDecimal(redPacketDto.getTotalAmount());
        final BigDecimal count = new BigDecimal(redPacketDto.getTotalCount());
        final BigDecimal divide = total.divide(count, 3, RoundingMode.HALF_UP);
        if (divide.compareTo(BigDecimal.valueOf(0.01))<0){
            return "输入不合法";
        }
        if (divide.compareTo(BigDecimal.valueOf(0.01))==0){
            redPacketDto.setIsOnlyMinAmount(1);
        }

        //调用第三方支付扣减用户余额
        userClientFacade.deduction(redPacketDto);

        //生成红包ID
        redPacketDto.setRedPacketId(String.valueOf(uidGenerator.getUID()));

        final RedPacketDomain domain = RedPacketAdaptor.toDomain(redPacketDto);
        //红包信息写redis，
        redPacketFacade.saveRedPacketToCache(domain);

        //红包信息写数据库
        redPacketFacade.saveRedPacketToDb(domain);

        return redPacketDto.getRedPacketId();
    }

    @Override
    public String grabRedPacket(final GrabRedPacketDto dto) {
        //调用抢红包服务
        final GrabRedPacketDomain domain = GrabRedPacketAdaptor.toDomain(dto);
        domain.setGrabTime(LocalDateTime.now().format(DateUtil.NORMAL_FORMATTER));
        Integer res = redPacketFacade.grab(domain);
        return  switch (res) {
            //判断结果 处理已抢光
            case -1 -> "已抢光";
            //判断结果 处理已抢过
            case 1 -> "已抢过";
            case 200 ->{
                //抢红包信息发mq消息
                Integer result = redPacketFacade.sendMq(domain);
                if (result==-1){
                    // TODO 处理发送mq失败
                    // 异步保持到db
                    redPacketFacade.saveGrabToDb(domain);
                    redPacketFacade.updateResidual(domain.getRedPacketId(),domain.getMoney());
                }
                yield  "抢到了:%s元".formatted(domain.getMoney());
            }
            default -> {
                throw new IllegalStateException("Unexpected value: " + res);
            }
        };
    }

    /**
     *         优先本地缓存获取,本地缓存没有，从redis获取
     *         本地和redis都没有，从infra获取，重新计算后加载缓存
     * @date 2024/4/20 15:52
     * @param redPacketId
     * @return com.houger.ddd.redpacket.controller.vo.GrabRedPacketResVo
     */
    @Caching(cacheable = {@Cacheable(value = "grabRedPacketResCache",key = "#redPacketId",cacheManager = "caffeineCacheManager"),
        @Cacheable(value = "grabRedPacketResCache",key = "#redPacketId",cacheManager = "redisCacheManager")})
    @Override
    public GrabRedPacketResVo getGrabRedPacketList(final String redPacketId) {
        final RedPacketDto redPacketDto= redPacketFacade.getRedPacketInfo(redPacketId);
        final GrabRedPacketResVo res = GrabRedPacketResVo.builder()
            .redPacketId(redPacketId)
            .totalAmount(redPacketDto.getTotalAmount())
            .totalCount(redPacketDto.getTotalCount())
            .sendTime(redPacketDto.getSendTime())
            .burnoutTime(redPacketDto.getBurnoutTime())
            .residualAmount(redPacketDto.getResidualAmount())
            .residualCount(redPacketDto.getResidualCount())
            .build();
        res.setConsumingSeconds();

        List<GrabRedPacketDto> grabList = redPacketFacade.getGrabRedPacketList(redPacketId);

        // 还有红包时直接返回，不用计算谁手气最佳
        if (!"0".equals(redPacketDto.getResidualCount())){
            res.setGrabRedPacketDtoList(grabList);
            return res;
        }
        // 计算谁手气最佳
        final BigDecimal bigDecimal = grabList.stream().map(GrabRedPacketDto::getMoney)
            .map(BigDecimal::new).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);

        for (GrabRedPacketDto grabRedPacketDto : grabList) {
            if (grabRedPacketDto.getMoney().equals(bigDecimal.toString())){
                grabRedPacketDto.setBestLuck("手气最佳");
                break;
            }
        }
        res.setGrabRedPacketDtoList(grabList);
        return res;
    }
}
